
package com.android.finaltracer.servercall;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.MarshalFloat;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import android.os.RemoteException;
import android.util.Log;

import com.android.finaltracer.util.Bean;

/**
 * @author guhl1
 */
class WSRemote implements RemoteCall {
    private final static String TAG = WSRemote.class.getSimpleName();

    private final static String NAME_SPACE = "http://ws.lenovo.com";
    private final static String SERVICE_URL = "http://211.151.79.218:8080/axis2/services/GPSService";

    @SuppressWarnings("unchecked")
    @Override
    public <T> List<T> execute(String action, Map<String, Object> req,
            Class<T> resultClass) throws RemoteException {
        if (ACTION_UPDATE_GPS.equals(action)) {
            updateGPS(req);
        } else if (ACTION_GET_GPS.equals(action)) {
            SoapObject request = new SoapObject(NAME_SPACE, "getGPS");
            SoapSerializationEnvelope env = new SoapSerializationEnvelope(
                    SoapEnvelope.VER11);
            registerData(req, request, env);
            HttpTransportSE trans = new HttpTransportSE(SERVICE_URL);
            trans.debug = true;
            try {
                trans.call("", env);
                List<T> resultList = new ArrayList<T>();
                Object response = env.getResponse();
                if (response instanceof SoapObject) {
                    SoapObject so = (SoapObject) response;
                    resultList.add(soapObject2Real(so, resultClass));
                } else if (response instanceof Vector) {
                    Vector<SoapObject> vec = (Vector<SoapObject>) response;
                    for (Iterator<SoapObject> it = vec.iterator(); it.hasNext();) {
                        SoapObject soapObject = it.next();
                        resultList
                                .add(soapObject2Real(soapObject, resultClass));
                    }
                }
                return resultList;

            } catch (Exception e) {
                Log.e(TAG, "updateGPS error", e);
                if (trans.debug) {
                    Log.i(TAG, "request soap: \n" + trans.requestDump);
                    Log.i(TAG, "response soap: \n" + trans.responseDump);
                }
                throw new RemoteException();
            }
        } else if (ACTION_HEARTBEAT.equals(action)) {
            return heartbeat();
        }
        return null;
    }

    @SuppressWarnings("rawtypes")
    private <T> List heartbeat() throws RemoteException {
        SoapObject request = new SoapObject(NAME_SPACE, "heartbeat");
        SoapSerializationEnvelope env = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);
        env.setOutputSoapObject(request);
        HttpTransportSE trans = new HttpTransportSE(SERVICE_URL);
        trans.debug = true;
        List<Boolean> result = new ArrayList<Boolean>();
        try {
            trans.call("", env);
            SoapPrimitive sp = (SoapPrimitive) env.getResponse();
            if ("true".equals(sp.toString())) {
                result.add(Boolean.TRUE);
                return result;
            }
        } catch (IOException e) {
            Log.e(TAG, "updateGPS error", e);
            if (trans.debug) {
                Log.i(TAG, "request soap: \n" + trans.requestDump);
                Log.i(TAG, "response soap: \n" + trans.responseDump);
            }
            throw new RemoteException();
        } catch (XmlPullParserException e) {
            Log.e(TAG, "heartbeat", e);
        }
        if (trans.debug) {
            Log.i(TAG, "request soap: \n" + trans.requestDump);
            Log.i(TAG, "response soap: \n" + trans.responseDump);
        }
        result.add(Boolean.FALSE);
        return result;
    }

    private <T> T soapObject2Real(SoapObject so, Class<T> clazz) {
        Map<String, String> result = new HashMap<String, String>();
        PropertyInfo info = new PropertyInfo();
        for (int i = 0; i < so.getPropertyCount(); i++) {
            so.getPropertyInfo(i, info);
            result.put(info.getName(), info.getValue().toString());
            info.clear();
        }
        return Bean.map2Bean(result, clazz);
    }

    private void updateGPS(Map<String, Object> args) throws RemoteException {
        SoapObject request = new SoapObject(NAME_SPACE, "updateGPS");
        SoapSerializationEnvelope env = new SoapSerializationEnvelope(
                SoapEnvelope.VER11);
        registerData(args, request, env);
        HttpTransportSE trans = new HttpTransportSE(SERVICE_URL);
        trans.debug = true;
        try {
            trans.call("", env);
        } catch (IOException e) {
            Log.e(TAG, "updateGPS error", e);
            if (trans.debug) {
                Log.i(TAG, "request soap: \n" + trans.requestDump);
                Log.i(TAG, "response soap: \n" + trans.responseDump);
            }
            throw new RemoteException();
        } catch (XmlPullParserException e) {
            // e.printStackTrace(); //for void method call,always throws such
            // exception
        }
        if (trans.debug) {
            Log.i(TAG, "request soap: \n" + trans.requestDump);
            Log.i(TAG, "response soap: \n" + trans.responseDump);
        }
    }

    private void registerData(Map<String, Object> args, SoapObject request,
            SoapSerializationEnvelope env) {
        boolean hasComplexNum = false;
        for (Iterator<String> it = args.keySet().iterator(); it.hasNext();) {
            String key = it.next();
            Object value = args.get(key);
            if (value instanceof String || value instanceof Integer
                    || value == null) {
                request.addProperty(key, value);
            } else if (value instanceof Double || value instanceof Long) {
                PropertyInfo pi = new PropertyInfo();
                pi.setName(key);
                pi.setType(value.getClass());
                pi.setValue(value);
                request.addProperty(pi);
                hasComplexNum = true;
            } else {
                throw new RuntimeException(value.getClass().getSimpleName()
                        + " not supported yet");
            }
        }
        env.setOutputSoapObject(request);
        if (hasComplexNum) {
            new MarshalFloat().register(env);
        }
    }
}
